package socket

import (
	"github.com/gorilla/websocket"
	"time"
	"net/http"
	"log"
	"github.com/gin-gonic/gin"
	"titargo/models"
	"encoding/json"
	"bytes"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512
)

var (
	newline = []byte{'\n'}
	space   = []byte{' '}
)

var wsupgrader = websocket.Upgrader{
	ReadBufferSize:   1024,
	WriteBufferSize:  1024,
	HandshakeTimeout: 5 * time.Second,
	// 取消ws跨域校验
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

type Client struct {
	hub *Hub

	conn *websocket.Conn

	send chan []byte

	user *models.User
}

func (c *Client) readPump() {
	defer func() {
		c.hub.unregister <- c
		c.conn.Close()
	}()

	for {
		_, message, err := c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("error:%v", err)
			}
			break;
		}
		var send_data = &SendData{}
		json.Unmarshal(message,&send_data)
		if send_data.MsgType == msg_type_bind{//绑定用户
			var user models.User
			db := models.GetEngine()
			db.Id(send_data.BindId).Get(&user)
			c.user = &user
		}else{//广播消息
			send_data.Sender = c.user
			send_data.CheckTime()
			newmessage,err := json.Marshal(send_data)
			if err != nil{
				panic(err)
			}else{
				newmessage = bytes.TrimSpace(bytes.Replace(newmessage, newline, space, -1))
				c.hub.broadcast <- newmessage
			}
		}

	}
}

func (c *Client) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.send:
			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if !ok {
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(message)

			n := len(c.send)
			for i := 0; i < n; i++ {
				w.Write(newline)
				w.Write(<-c.send)
			}

			if err := w.Close(); err != nil {
				return
			}
		case <-ticker.C:
			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

func WsHandler(user *models.User,hub *Hub, c *gin.Context) {
	conn, err := wsupgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}
	client := &Client{hub: hub, conn: conn, send: make(chan []byte, 256),user:user}
	client.hub.register <- client

	go client.writePump()
	go client.readPump()
}
